#include <random>
#include <iomanip>
#include <fstream>
#include <mutex>
#include <list>
#include "zlib.h"
#include <cstring>
#include <sstream>
// #define UNZIP_BUFF_SIZE 1024 * 1024

namespace Utils
{
    std::string GetNewUUID()
    {
        static std::random_device rd(std::to_string(time(NULL)));
        static std::uniform_int_distribution<uint64_t> dist(0ULL, 0xFFFFFFFFFFFFFFFFULL);
        uint64_t ab = dist(rd);
        uint64_t cd = dist(rd);
        uint32_t a, b, c, d;
        std::stringstream ss;
        ab = (ab & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL;
        cd = (cd & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL;
        a = (ab >> 32U);
        b = (ab & 0xFFFFFFFFU);
        c = (cd >> 32U);
        d = (cd & 0xFFFFFFFFU);
        ss << std::hex << std::nouppercase << std::setfill('0');
        ss << std::setw(8) << (a) << '-';
        ss << std::setw(4) << (b >> 16U) << '-';
        ss << std::setw(4) << (b & 0xFFFFU) << '-';
        ss << std::setw(4) << (c >> 16U) << '-';
        ss << std::setw(4) << (c & 0xFFFFU);
        ss << std::setw(8) << d;
        return ss.str();
    }

    /***********************************************************************************************************
     * @brief 读取文本文件的内容
     * @param path 文件位置
     * @param outStr 存储字符串的对象
     * @return true: 读取成功 | false: 读取失败
    ***********************************************************************************************************/
    bool LoadTextFile(const std::string &path, std::string &outStr)
    {
        //加载文件
        std::ifstream inputFile(path);
        if (inputFile)
        {
            std::stringstream buffer;
            buffer << inputFile.rdbuf();
            inputFile.close();
            outStr = buffer.str();
            return true;
        }
        inputFile.close();
        return false;
    }

    /***********************************************************************************************************
     * @brief 保存文本到文件
     * @param path 文件位置
     * @param inStr 内容
     * @return true: 保存成功 | false: 保存失败
    ***********************************************************************************************************/
    bool SaveTextFile(const std::string &path, const std::string &inStr)
    {
        std::ofstream outputFile(path);
        if (!outputFile.is_open())
        {
            outputFile.close();
            return false;
        }
        outputFile << inStr;
        outputFile.close();
        return true;
    }

    /***********************************************************************************************************
     * @brief 切割字符串
     * @param str 要切割的字符串
     * @param pattern 分个参数，例如:";"
     * @param res 存储容器
    ***********************************************************************************************************/
    void StringSplit(const std::string &str, const std::string &pattern, std::vector<std::string> &res)
    {
        if (str != "")
        {
            //在字符串末尾也加入分隔符，方便截取最后一段
            std::string strs = str + pattern;

            size_t pos = strs.find(pattern);
            while (pos != std::string::npos)
            {
                std::string temp = strs.substr(0, pos);
                res.push_back(temp);
                //去掉已分割的字符串,在剩下的字符串中进行分割
                strs = strs.substr(pos + pattern.length(), strs.size());
                pos = strs.find(pattern);
            }
        }
    }

    /***********************************************************************************************************
     * @brief 切割字符串
     * @param str 要切割的字符串
     * @param pattern 分个参数，例如:";"
     * @param res 存储容器
    ***********************************************************************************************************/
    void StringSplit(const std::string &str, const std::string &pattern, std::list<std::string> &res)
    {
        if (str != "")
        {
            //在字符串末尾也加入分隔符，方便截取最后一段
            std::string strs = str + pattern;

            size_t pos = strs.find(pattern);
            while (pos != std::string::npos)
            {
                std::string temp = strs.substr(0, pos);
                res.push_back(temp);
                //去掉已分割的字符串,在剩下的字符串中进行分割
                // strs = strs.substr(pos + pattern.length(), strs.size());
                // pos = strs.find(pattern);
                strs = strs.substr(pos + pattern.length(), strs.size());
                pos = strs.find(pattern);
            }
        }
    }


    /***********************************************************************************************************
     * @brief 十六进制数据转字符串形式
     * @param ptr 十六进制数据
     * @param length 数据长度
     * @return 字符串
    ***********************************************************************************************************/
    std::string ToHexString(const void* ptr, int32_t length)
    {
        static char *hexStringCatch = nullptr;
        static uint32_t hexCatchSize = 0; 

        if(hexCatchSize < length * 3)
        {
            delete[] hexStringCatch;
            int32_t size = length * 3 + 128;
            hexStringCatch = new char[size];
            hexCatchSize = size;
        }
        
        for(int32_t index = 0; index < length; index++)
        {
            sprintf(&(hexStringCatch[index * 3]),"%02X ",((const uint8_t *)ptr)[index]);
        }
        hexStringCatch[length * 3 - 1] = '\0';
        return hexStringCatch;
    }

    /***********************************************************************************************************
     * @brief 替换字符串中对应的子字符串
     * @param str 要进行替换的字符串
     * @param oldValue 要替换的子字符串
     * @param newValue 替换成的字符串
     * @return 替换好的字符串
    ***********************************************************************************************************/
    std::string StringReplace(const std::string &str, const std::string& oldValue, const std::string& newValue)
    {
        std::vector<std::string> splitStr;
        StringSplit(str, oldValue, splitStr);
        std::stringstream ss;
        ss << splitStr[0];
        for(int32_t index = 1; index < splitStr.size(); ++index)
        {
            ss << newValue << splitStr[index];
        }
        return ss.str();
    }

    /***********************************************************************************************************
     * @brief 解压数据，注：这里用的不是标准的zlib格式，解压zlib数据时需要掐头(2字节)去尾(4字节)
     * @param comBuf 压缩的数据
     * @param comSize 压缩的数据大小
     * @param buffer 用于存储解压出来的数据
     * @param bufferSize 解压缓存的大小
     * @return 解压出来的数据大小，0表示失败
    ***********************************************************************************************************/
    uint32_t RawInflateDecompresse(const void *comBuf, uint32_t comSize, void *buffer, uint32_t bufferSize)
    {
        z_stream  stream;
	    memset(&stream, 0, sizeof(z_stream));
	    stream.next_in = (Bytef*)(comBuf);
	    stream.avail_in = comSize;
	    stream.next_out = (Bytef* )buffer;
	    stream.avail_out = bufferSize;

	    inflateInit2(&stream, -MAX_WBITS);
	    int32_t result = inflate(&stream, Z_FINISH);
	    if (result != Z_STREAM_END && result != Z_OK) 
        {
	    	return  0;
	    }
	    inflateEnd(&stream);
        return stream.total_out;
    }

    /***********************************************************************************************************
     * @brief 压缩数据，注：这里用的不是标准的zlib格，无法使用标准的zlib解压
     * @param uncomBuf 要进行压缩的数据
     * @param uncomSize 要进行压缩的数据的大小
     * @param buffer 用于存储压缩数据
     * @param bufferSize 压缩缓存的大小
     * @return 压缩出来的数据大小，0表示失败
    ***********************************************************************************************************/
    uint32_t RawDeflateCompresse(const void *uncomBuf, uint32_t uncomSize, void *buffer, uint32_t bufferSize)
    {
        z_stream deflate_stream;
        memset(&deflate_stream, 0, sizeof(z_stream));
        deflate_stream.next_in = (Bytef *)uncomBuf;
        deflate_stream.avail_in =  uncomSize;
        deflate_stream.next_out = (Bytef *)buffer;
        deflate_stream.avail_out = bufferSize;

        deflateInit2(&deflate_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
        int32_t result = deflate(&deflate_stream, Z_FINISH);
        if (result != Z_STREAM_END && result != Z_OK) 
        {
            return 0;
        }
        deflateEnd(&deflate_stream);
        return deflate_stream.total_out;
    }

    /***********************************************************************************************************
     * @brief 十六进制字符转数字
     * @param c 十六进制字符
     * @return 例如:输入'f'，返回 15
    ***********************************************************************************************************/
    static char getCharValue(char c)
    {
        char value = -1;
        if(c >= '0' && c <= '9')
        {
            value = c - '0';
        }
        else if(c >= 'a' && c <= 'f')
        {
            value = c - 'a' + 10;
        }
        else if(c >= 'A' && c <= 'F')
        {
            value = c - 'A' + 10;
        }
        return value;
    }

    /***********************************************************************************************************
     * @brief 十六进制字符串转数组，例如:"AABb"这个字符串,将转成数组 [0]=0xAA, [1]=0xBB
     * @param str 对应十六进制字符的字符串(由'0'~'9'和'a'~'f'和'A'~'F'构成)
     * @param buff 用于存储转换出来的十六进制数据的缓存
     * @param buffSize 缓存大小
     * @return true 转换成功， false 转换失败
    ***********************************************************************************************************/
    bool StringToHex(const std::string& str, void * buff, uint32_t buffSize)
    {
        uint8_t offset = 0;
        uint8_t *catchBuff = (uint8_t *)buff;

        if(str.length() % 2 != 0)
        {
            offset = 1;
            catchBuff[0] = getCharValue(str[0]);
            if(catchBuff[0] == -1)
            {
                return false;
            }
        }
        int32_t charIndex = 0;
        for(int32_t index = 0; index < str.length() / 2; index++)
        {
            char value1 = getCharValue(str[charIndex + offset]);
            charIndex++;
            char value2 = getCharValue(str[charIndex + offset]);
            charIndex++;
            if(value1 == -1 || value2 == -1)
            {
                return false;
            }
            value1 = (value1 << 4) | value2;
            catchBuff[index + offset] = value1;
        }
        return true;
    }

}